package com.junxonline.plat.shiro;


import com.junxonline.common.util.JWTUtils;
import com.junxonline.common.util.NetWorkUtils;
import com.junxonline.plat.dao.SystemUserDAO;
import com.junxonline.plat.jwt.JWTToken;
import com.junxonline.plat.model.SystemMenu;
import com.junxonline.plat.model.SystemRole;
import com.junxonline.plat.model.SystemUser;
import com.junxonline.plat.service.exception.PlatBizException;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * @author JunX
 * @ClassName: DefaultRealm
 * @Description: 默认安全域
 */

public class DefaultRealm extends AuthorizingRealm {

    @Resource
    private SystemUserDAO systemUserDAO;

    /**
     * 认证
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = (String) authenticationToken.getCredentials();
        // 解密获得username，用于和数据库进行对比
        String username = JWTUtils.getUsername(token);
        if (null == username) {
            throw PlatBizException.TOKEN_AUTH_IS_ERROR;
        }

        SystemUser systemUser = systemUserDAO.findByUsername(username);
        if (null == systemUser) {
            throw PlatBizException.ACCOUNT_IS_NOT_FINDED;
        }

        if (! JWTUtils.verify(token, username, systemUser.getPassword())) {
            throw PlatBizException.ACCOUNT_OR_PASSWORD_IS_ERROR;
        }

        // 通过认证后做的事情 视为登录成功
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            // 更新最后登录IP地址和时间
            systemUser.setLastLoginTime(new Date(System.currentTimeMillis()));
            systemUser.setLastLoginIp(NetWorkUtils.getIpAddress(request));
            systemUserDAO.save(systemUser);
        } catch (Exception e) {
            throw PlatBizException.SYSTEM_ERROR;
        }

        return new SimpleAuthenticationInfo(token, token, getName());
    }

    /**
     * 授权
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String username = JWTUtils.getUsername(principalCollection.toString());
        if (null == username) {
            throw PlatBizException.TOKEN_AUTH_IS_ERROR;
        }
        SystemUser systemUser = systemUserDAO.findByUsername(username);
        if (null == systemUser) {
            throw PlatBizException.ACCOUNT_IS_NOT_FINDED;
        }

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        for (SystemRole role : systemUser.getRoles()) {
            authorizationInfo.addRole(role.getRoleKey());
            for (SystemMenu menu : role.getMenus()) {
                authorizationInfo.addStringPermission(menu.getMenuPermission());
            }
        }

        return authorizationInfo;
    }

    /**
     * 大坑！，必须重写此方法，不然Shiro会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken;
    }

}
